package com.hly.poitool.word;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STPositiveCoordinate;
import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;
import org.openxmlformats.schemas.drawingml.x2006.picture.CTPictureNonVisual;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTEffectExtent;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.*;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author : Jack Hao
 * @Date : 2022/3/29 10:49
 * @description :
 */

public class PoiConvertWord2 {


    /**
     * 把源文件中的的段落 表格 图片 合并到 目标文件中
     *
     * @param sourceFilePath 源文件路径
     * @param targetFilePath 目标文件路径
     * @param matchKey       匹配用的字符
     * @return
     */
    public static void convert(String sourceFilePath, String targetFilePath, String matchKey) throws Exception {
        //源文件的 XWPFDocument 对象
        ReentrantLock lock = new ReentrantLock();
        XWPFDocument document = null;
        try {
            lock.lock();

            document = getDocument(sourceFilePath);

            //源文件中的所有数据
            List<IBodyElement> bodyElements = document.getBodyElements();

            //源文件中的段落
            List<XWPFParagraph> paraList = document.getParagraphs();

            //源文件中表格
            List<XWPFTable> tables = document.getTables();

//            //源文件中的图片
//            List<XWPFPictureData> pictures = document.getAllPictures();

            // 把原文将中的所有数据添加到目标文件中
            //setRed(bodyElements, paraList, tables, pictures, targetFilePath, matchKey);
            setRed(bodyElements, paraList, tables, targetFilePath, matchKey);

        } finally {
            try {
                lock.unlock();
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (document != null) {
                try {
                    document.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }


    /**
     * 把源文件中的的段落 表格 图片 合并到 目标文件中
     *
     * @param document       源文件对象
     * @param targetDocument 目标文件对象
     * @param targetFilePath 目标文件路径
     * @param matchKey       匹配用的字符
     * @return
     */
    public static void convert(XWPFDocument document, XWPFDocument targetDocument, String targetFilePath, String matchKey) throws Exception {
        ReentrantLock lock = new ReentrantLock();
        try {
            lock.lock();

            //源文件中的所有数据
            List<IBodyElement> bodyElements = document.getBodyElements();

            //源文件中的段落
            List<XWPFParagraph> paraList = document.getParagraphs();

            //源文件中表格
            List<XWPFTable> tables = document.getTables();

//            //源文件中的图片
//            List<XWPFPictureData> pictures = document.getAllPictures();

            // 把原文将中的所有数据添加到目标文件中
            //setRed(bodyElements, paraList, tables, pictures, targetDocument, targetFilePath, matchKey);
            setRed(bodyElements, paraList, tables, targetDocument, targetFilePath, matchKey);

        } finally {
            try {
                lock.unlock();
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (document != null) {
                try {
                    document.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }


    /**
     * 获取 body Element 中的 段落 表格 和 图片
     *
     * @param bodyElements   源文件 的 body 节点
     * @param paraList       源文件 的段落集合
     * @param tables         源文件 的表格集合
     *                       //* @param pictures       源文件 的图片集合
     * @param targetFilePath 目标文件的路径
     * @param matchKey       匹配用的标识符
     * @return
     * @throws Exception
     */
    public static boolean setRed(List<IBodyElement> bodyElements, List<XWPFParagraph> paraList, List<XWPFTable> tables, String targetFilePath, String matchKey) throws Exception {
        XWPFDocument targetDocument = null;//构建模板文档对象
        FileOutputStream fileOutputStream = null;
        try {
            //使用 byte 数组 新建 XWPFDocument 对象
            targetDocument = getDocument(targetFilePath);

            //获取目标文件的所有段落对象
            List<XWPFParagraph> targetParas = targetDocument.getParagraphs();
            List<IBodyElement> targetBodyEles = targetDocument.getBodyElements();

            //匹配到的段落的位置
            int startPoint = getPoint(targetParas, matchKey);

            if (startPoint != 0) {

                XWPFParagraph insertNewParagraph = targetParas.get(startPoint);//获取到标记位置的段落对象
                XmlCursor xmlCursor = insertNewParagraph.getCTP().newCursor();//获取到段落的光标


                int paraIndex = 1;
                int tableIndex = 0;
                //int pictureIndex = 0;

                int targetTableIndex = getTitleTableIndex(targetBodyEles, targetParas, matchKey);
                xmlCursor.toNextSibling();//下移光标
                insertNewParagraph = targetDocument.insertNewParagraph(xmlCursor);//在当前光标处插入新的段落
                xmlCursor = insertNewParagraph.getCTP().newCursor();

                int beSize = bodyElements.size();
                for (int j = 1; j < beSize; j++) {
                    xmlCursor.toNextSibling();//下移光标

                    IBodyElement iBodyElement = bodyElements.get(j);//获得传过来的段落对象
                    BodyElementType elementType = iBodyElement.getElementType();
                    if (elementType.equals(BodyElementType.PARAGRAPH)) {//判断 文件 body 中当前节点 是段落
                        insertNewParagraph = targetDocument.insertNewParagraph(xmlCursor);//在当前光标处插入新的段落
                        xmlCursor = insertNewParagraph.getCTP().newCursor();
                        //源文件中 第 paraIndex 个 段落
                        XWPFParagraph xwpfParagraph_i = paraList.get(paraIndex);
                        paraIndex++;

                        //复制段落
                        copyParagraph(xwpfParagraph_i, insertNewParagraph);

                    } else if (elementType.equals(BodyElementType.TABLE)) {//判断 文件 body 中当前节点 是表格

                        //复制table
                        XWPFTable indexTable = tables.get(tableIndex);
                        tableIndex++;

                        XWPFTable xwpfTable = targetDocument.insertNewTbl(xmlCursor);
                        //table 添加边框
                        addTableBoder(indexTable);
                        targetDocument.setTable(targetTableIndex, indexTable);
                        targetTableIndex++;
                        xmlCursor = xwpfTable.getCTTbl().newCursor();
                    }

                }
            }

            fileOutputStream = new FileOutputStream(targetFilePath);
            targetDocument.write(fileOutputStream);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (targetDocument != null) {
                try {
                    targetDocument.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return true;
    }


    /**
     * 获取 body Element 中的 段落 表格 和 图片
     *
     * @param bodyElements   源文件 的 body 节点
     * @param paraList       源文件 的段落集合
     * @param tables         源文件 的表格集合
     *                       //* @param pictures       源文件 的图片集合
     * @param targetDocument 目标文件的对象
     * @param targetFilePath 目标文件的对象
     * @param matchKey       匹配用的标识符
     * @return
     * @throws Exception
     */
    public static boolean setRed(List<IBodyElement> bodyElements, List<XWPFParagraph> paraList, List<XWPFTable> tables, XWPFDocument targetDocument, String targetFilePath, String matchKey) throws Exception {
        FileOutputStream fileOutputStream = null;
        try {

            //获取目标文件的所有段落对象
            List<XWPFParagraph> targetParas = targetDocument.getParagraphs();
            List<IBodyElement> targetBodyEles = targetDocument.getBodyElements();

            //匹配到的段落的位置
            int startPoint = getPoint(targetParas, matchKey);

            if (startPoint != 0) {

                XWPFParagraph insertNewParagraph = targetParas.get(startPoint);//获取到标记位置的段落对象
                XmlCursor xmlCursor = insertNewParagraph.getCTP().newCursor();//获取到段落的光标


                int paraIndex = 1;
                int tableIndex = 0;
                //int pictureIndex = 0;

                int targetTableIndex = getTitleTableIndex(targetBodyEles, targetParas, matchKey);
                xmlCursor.toNextSibling();//下移光标
                insertNewParagraph = targetDocument.insertNewParagraph(xmlCursor);//在当前光标处插入新的段落
                xmlCursor = insertNewParagraph.getCTP().newCursor();


                int beSize = bodyElements.size();
                for (int j = 1; j < beSize; j++) {
                    xmlCursor.toNextSibling();//下移光标
                    IBodyElement iBodyElement = bodyElements.get(j);//获得传过来的段落对象
                    BodyElementType elementType = iBodyElement.getElementType();
                    if (elementType.equals(BodyElementType.PARAGRAPH)) {//判断 文件 body 中当前节点 是段落

                        insertNewParagraph = targetDocument.insertNewParagraph(xmlCursor);//在当前光标处插入新的段落
                        xmlCursor = insertNewParagraph.getCTP().newCursor();

                        //源文件中 第 paraIndex 个 段落
                        XWPFParagraph xwpfParagraph_i = paraList.get(paraIndex);
                        paraIndex++;
                        //复制段落
                        copyParagraph(xwpfParagraph_i, insertNewParagraph);

                    } else if (elementType.equals(BodyElementType.TABLE)) {//判断 文件 body 中当前节点 是表格
                        //复制table
                        XWPFTable indexTable = tables.get(tableIndex);
                        tableIndex++;

                        XWPFTable xwpfTable = targetDocument.insertNewTbl(xmlCursor);
                        //table 添加边框
                        addTableBoder(indexTable);
                        targetDocument.setTable(targetTableIndex, indexTable);
                        targetTableIndex++;
                        xmlCursor = xwpfTable.getCTTbl().newCursor();
                    }

                }
            }

            fileOutputStream = new FileOutputStream(targetFilePath);
            targetDocument.write(fileOutputStream);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return true;
    }


    /**
     * table 添加边框
     *
     * @param table
     */
    private static void addTableBoder(XWPFTable table) {

        CTTbl ctTbl = table.getCTTbl();
        CTTblPr tblPr = ctTbl.getTblPr();
        if (tblPr == null) {
            tblPr = ctTbl.addNewTblPr();
        }
        boolean setTblBorders = tblPr.isSetTblBorders();
        if (setTblBorders) {
            return;
        }
        CTTblBorders borders = tblPr.addNewTblBorders();
        CTBorder hBorder = borders.addNewInsideH();
        hBorder.setVal(STBorder.Enum.forString("single")); // 线条类型
        hBorder.setSz(new BigInteger("1")); // 线条大小
        hBorder.setColor("000000"); // 设置颜色

        CTBorder vBorder = borders.addNewInsideV();
        vBorder.setVal(STBorder.Enum.forString("single"));
        vBorder.setSz(new BigInteger("1"));
        vBorder.setColor("000000");

        CTBorder lBorder = borders.addNewLeft();
        lBorder.setVal(STBorder.Enum.forString("single"));
        lBorder.setSz(new BigInteger("1"));
        lBorder.setColor("000000");

        CTBorder rBorder = borders.addNewRight();
        rBorder.setVal(STBorder.Enum.forString("single"));
        rBorder.setSz(new BigInteger("1"));
        rBorder.setColor("000000");

        CTBorder tBorder = borders.addNewTop();
        tBorder.setVal(STBorder.Enum.forString("single"));
        tBorder.setSz(new BigInteger("1"));
        tBorder.setColor("000000");

        CTBorder bBorder = borders.addNewBottom();
        bBorder.setVal(STBorder.Enum.forString("single"));
        bBorder.setSz(new BigInteger("1"));
        bBorder.setColor("000000");

    }


    /**
     * 复制 源文件中的段落到目标文件 段落有两种 一种是文字 另一种是图片 需要进行判断
     *
     * @param sourceParagraph 源文件的段落
     * @param targetParagraph 目标文件的段落
     *                        //* @param pictures        图片集合
     *                        //* @param pictureIndex    获取到图标的下角标
     * @return
     * @throws IOException
     * @throws InvalidFormatException
     */
    public static void copyParagraph(XWPFParagraph sourceParagraph, XWPFParagraph targetParagraph) throws IOException, InvalidFormatException {
        List<XWPFRun> runs = sourceParagraph.getRuns();//获取run对象

        Borders borderLeft = sourceParagraph.getBorderLeft();
        targetParagraph.setBorderLeft(borderLeft);

        int indentationLeft = sourceParagraph.getIndentationLeft();
        int indentFromLeft = sourceParagraph.getIndentFromLeft();
        int indentationFirstLine = sourceParagraph.getIndentationFirstLine();
        int indentationHanging = sourceParagraph.getIndentationHanging();

        targetParagraph.setIndentationLeft(indentationLeft);
        targetParagraph.setIndentFromLeft(indentFromLeft);
        targetParagraph.setIndentationFirstLine(indentationFirstLine);
        targetParagraph.setIndentationHanging(indentationHanging);


        //复制源段落样式到新的段落
        ParagraphAlignment alignment = sourceParagraph.getAlignment();
        if (alignment != null) {
            targetParagraph.setAlignment(alignment);
        }

        for (int k = 0; k < runs.size(); k++) {

            XWPFRun oldRun = runs.get(k);
            CTR oldCtr = oldRun.getCTR();
            List<CTDrawing> drawingList = oldCtr.getDrawingList();
            CTRPr oldRPr = oldCtr.getRPr();
            if (oldRPr != null) {
                CTRPrChange oldRPrChange = oldRPr.getRPrChange();//run标签里也有rprchange标签也需要像上面一样设置
                if (oldRPrChange != null) {
                    oldRPr.unsetRPrChange();
                }
            }
            XWPFRun newRun = targetParagraph.createRun();
            if (oldRPr != null) {
                newRun.getCTR().setRPr(oldRPr);
            }

            if (drawingList.size() > 0) { //判断是图片 复制图片

                targetParagraph.setIndentFromLeft(indentationFirstLine);//---整段右移

                List<XWPFPicture> embeddedPictures = oldRun.getEmbeddedPictures();
                XWPFPicture xwpfPicture = embeddedPictures.get(0);

                XWPFPictureData pictureData = xwpfPicture.getPictureData();

                CTDrawing drawing = drawingList.get(0);
                List<CTInline> inlineList = drawing.getInlineList();
                CTInline ctInline = inlineList.get(0);

                CTPositiveSize2D extent = ctInline.getExtent();

                long cx = extent.getCx();
                long cy = extent.getCy();

                //图片在word中的宽
                int w = new Long(cx).intValue();
                //图片在word中的高
                int y = new Long(cy).intValue();
//
//                if(pictureIndex>=pictures.size()){
//                    return;
//                }
//                XWPFPictureData xwpfPictureData = pictures.get(pictureIndex);
                //pictureIndex++;
//                byte[] data = xwpfPictureData.getData();

                byte[] data = pictureData.getData();

                String picName = "drw-" + UUID.randomUUID().toString();
                newRun.addPicture(new ByteArrayInputStream(data), XWPFDocument.PICTURE_TYPE_PNG, picName, w, y);

            } else {//不是图片 复制文字
                String text = oldRun.text();
                newRun.setText(text);
            }
            targetParagraph.addRun(newRun);
        }
    }
//
//
//    /**
//     * 复制 源文件中的段落到目标文件 段落有两种 一种是文字 另一种是图片 需要进行判断
//     *
//     * @param sourceParagraph 源文件的段落
//     * @param targetParagraph 目标文件的段落
//     * @param pictures        图片集合
//     * @param pictureIndex    获取到图标的下角标
//     * @return
//     * @throws IOException
//     * @throws InvalidFormatException
//     */
//    public static void copyParagraph(XWPFParagraph sourceParagraph, XWPFParagraph targetParagraph, List<XWPFPictureData> pictures, int pictureIndex) throws IOException, InvalidFormatException {
//        List<XWPFRun> runs = sourceParagraph.getRuns();//获取run对象
//
//        Borders borderLeft = sourceParagraph.getBorderLeft();
//        targetParagraph.setBorderLeft(borderLeft);
//
//        int indentationLeft = sourceParagraph.getIndentationLeft();
//        int indentFromLeft = sourceParagraph.getIndentFromLeft();
//        int indentationFirstLine = sourceParagraph.getIndentationFirstLine();
//        int indentationHanging = sourceParagraph.getIndentationHanging();
//
//        targetParagraph.setIndentationLeft(indentationLeft);
//        targetParagraph.setIndentFromLeft(indentFromLeft);
//        targetParagraph.setIndentationFirstLine(indentationFirstLine);
//        targetParagraph.setIndentationHanging(indentationHanging);
//
//
//        //复制源段落样式到新的段落
//        ParagraphAlignment alignment = sourceParagraph.getAlignment();
//        if (alignment != null) {
//            targetParagraph.setAlignment(alignment);
//        }
//
//        for (int k = 0; k < runs.size(); k++) {
//
//            XWPFRun oldRun = runs.get(k);
//            CTR oldCtr = oldRun.getCTR();
//            List<CTDrawing> drawingList = oldCtr.getDrawingList();
//            CTRPr oldRPr = oldCtr.getRPr();
//            if (oldRPr != null) {
//                CTRPrChange oldRPrChange = oldRPr.getRPrChange();//run标签里也有rprchange标签也需要像上面一样设置
//                if (oldRPrChange != null) {
//                    oldRPr.unsetRPrChange();
//                }
//            }
//            XWPFRun newRun = targetParagraph.createRun();
//            if (oldRPr != null) {
//                newRun.getCTR().setRPr(oldRPr);
//            }
//
//            if (drawingList.size() > 0) { //判断是图片 复制图片
//
//                List<XWPFPicture> embeddedPictures = oldRun.getEmbeddedPictures();
//                XWPFPicture xwpfPicture = embeddedPictures.get(0);
//                XWPFPictureData pictureData = xwpfPicture.getPictureData();
////                CTPicture ctPicture = xwpfPicture.getCTPicture();
////                CTShapeProperties spPr = ctPicture.getSpPr();
////                spPr.get
////
//                CTDrawing drawing = drawingList.get(0);
//                List<CTInline> inlineList = drawing.getInlineList();
//                CTInline ctInline = inlineList.get(0);
//                CTPositiveSize2D extent = ctInline.getExtent();
//
//                long cx = extent.getCx();
//                long cy = extent.getCy();
//
//                //图片在word中的宽
//                int w = new Long(cx).intValue();
//                //图片在word中的高
//                int y = new Long(cy).intValue();
////
////                if(pictureIndex>=pictures.size()){
////                    return;
////                }
////                XWPFPictureData xwpfPictureData = pictures.get(pictureIndex);
//                //pictureIndex++;
////                byte[] data = xwpfPictureData.getData();
//
//                byte[] data = pictureData.getData();
//
//                String picName = "drw-" + UUID.randomUUID().toString();
//                newRun.addPicture(new ByteArrayInputStream(data), XWPFDocument.PICTURE_TYPE_PNG, picName, w, y);
//
//
//            } else {//不是图片 复制文字
//                String text = oldRun.text();
//                newRun.setText(text);
//            }
//            targetParagraph.addRun(newRun);
//        }
//    }

    /**
     * 检查段落中是不是图片
     *
     * @param sourceParagraph 源文件的段落
     * @return
     * @throws IOException
     * @throws InvalidFormatException
     */
    public static boolean checkParagraphPicture(XWPFParagraph sourceParagraph) {
        boolean flag = false;
        List<XWPFRun> runs = sourceParagraph.getRuns();//获取run对象
        for (int k = 0; k < runs.size(); k++) {
            XWPFRun oldRun = runs.get(k);
            CTR oldCtr = oldRun.getCTR();
            List<CTDrawing> drawingList = oldCtr.getDrawingList();
            if (drawingList.size() > 0) { //判断是图片 复制图片
                flag = true;
                break;
            }
        }
        return flag;
    }

//    /**
//     * 添加标题
//     *
//     * @param sourceParagraph 源文件的段落
//     * @param targetParagraph 目标文件的段落
//     * @param titleStr        标题内容
//     * @return
//     * @throws IOException
//     * @throws InvalidFormatException
//     */
//    public static void addSubTitle(XWPFParagraph sourceParagraph, XWPFParagraph targetParagraph, String titleStr) {
//        //复制源段落样式到新的段落
//        ParagraphAlignment alignment = sourceParagraph.getAlignment();
//        if (alignment != null) {
//            targetParagraph.setAlignment(alignment);
//        }
//        XWPFRun newRun = targetParagraph.createRun();
//        newRun.setText(titleStr);
//        targetParagraph.addRun(newRun);
//    }

    /**
     * 复制 源文件中的段落到目标文件 段落有两种 一种是文字 另一种是图片 需要进行判断
     *
     * @param sourceParagraph 源文件的段落
     * @param targetParagraph 目标文件的段落
     * @param pictures        图片集合
     * @param pictureIndex    获取到图标的下角标
     * @return
     * @throws IOException
     * @throws InvalidFormatException
     */
    public static void 上copyParagraphAutoIncrem(XWPFParagraph sourceParagraph, XWPFParagraph targetParagraph, List<XWPFPictureData> pictures, int pictureIndex) throws IOException, InvalidFormatException {
        List<XWPFRun> runs = sourceParagraph.getRuns();//获取run对象

        //复制源段落样式到新的段落
        ParagraphAlignment alignment = sourceParagraph.getAlignment();
        if (alignment != null) {
            targetParagraph.setAlignment(alignment);
        }

        for (int k = 0; k < runs.size(); k++) {

            XWPFRun oldRun = runs.get(k);
            CTR oldCtr = oldRun.getCTR();
            List<CTDrawing> drawingList = oldCtr.getDrawingList();
            CTRPr oldRPr = oldCtr.getRPr();
            if (oldRPr != null) {
                CTRPrChange oldRPrChange = oldRPr.getRPrChange();//run标签里也有rprchange标签也需要像上面一样设置
                if (oldRPrChange != null) {
                    oldRPr.unsetRPrChange();
                }
            }
            XWPFRun newRun = targetParagraph.createRun();
            if (oldRPr != null) {
                newRun.getCTR().setRPr(oldRPr);
            }

            if (drawingList.size() > 0) { //判断是图片 复制图片

                CTDrawing drawing = drawingList.get(0);
                List<CTInline> inlineList = drawing.getInlineList();
                CTInline ctInline = inlineList.get(0);
                CTPositiveSize2D extent = ctInline.getExtent();
                long cx = extent.getCx();
                long cy = extent.getCy();

                //图片在word中的宽
                int w = new Long(cx).intValue();
                //图片在word中的高
                int y = new Long(cy).intValue();

                if (pictureIndex >= pictures.size()) {
                    return;
                }
                XWPFPictureData xwpfPictureData = pictures.get(pictureIndex);
                pictureIndex++;
                byte[] data = xwpfPictureData.getData();

                String picName = "drw-" + UUID.randomUUID().toString();
                newRun.addPicture(new ByteArrayInputStream(data), XWPFDocument.PICTURE_TYPE_PNG, picName, w, y);

            } else {//不是图片 复制文字
                String text = oldRun.text();
                newRun.setText(text);
            }
            targetParagraph.addRun(newRun);
        }
    }
//
//    /**
//     * 复制 源文件中的段落到目标文件 段落有两种 一种是文字 另一种是图片 需要进行判断
//     *
//     * @param sourceParagraph 源文件的段落
//     * @param targetParagraph 目标文件的段落
//     * @return
//     * @throws IOException
//     * @throws InvalidFormatException
//     */
//    public static void copyParagraph(XWPFParagraph sourceParagraph, XWPFParagraph targetParagraph) {
//        List<XWPFRun> runs = sourceParagraph.getRuns();//获取run对象
//        
//        //复制源段落样式到新的段落
//        ParagraphAlignment alignment = sourceParagraph.getAlignment();
//        if (alignment != null) {
//            targetParagraph.setAlignment(alignment);
//        }
//
//
//        String numLevelText = sourceParagraph.getNumLevelText();
//        BigInteger numIlvl = sourceParagraph.getNumIlvl();
//        String numFmt = sourceParagraph.getNumFmt();
//        if (isNotNullAndNotEmpty(numLevelText)) {
//            targetParagraph.setNumID(numIlvl);
//        }
//
//
//        for (int k = 0; k < runs.size(); k++) {
//
//            XWPFRun oldRun = runs.get(k);
//            CTR oldCtr = oldRun.getCTR();
//            List<CTDrawing> drawingList = oldCtr.getDrawingList();
//            CTRPr oldRPr = oldCtr.getRPr();
//            if (oldRPr != null) {
//                CTRPrChange oldRPrChange = oldRPr.getRPrChange();//run标签里也有rprchange标签也需要像上面一样设置
//                if (oldRPrChange != null) {
//                    oldRPr.unsetRPrChange();
//                }
//            }
//            XWPFRun newRun = targetParagraph.createRun();
//            if (oldRPr != null) {
//                newRun.getCTR().setRPr(oldRPr);
//            }
//
//            if (drawingList.size() > 0) { //判断是图片 复制图片
//                //不处理图片
//            } else {//不是图片 复制文字
//                String text = oldRun.text();
//                newRun.setText(text);
//            }
//            targetParagraph.addRun(newRun);
//        }
//    }


//    /**
//     * 复制 源文件中的 table 到 目标文件
//     *
//     * @param targetDocument 目标文件 document 对象
//     * @param xmlCursor      目标文件的光标
//     * @param xwpfTable      源文件的  table
//     * @return 返回光标
//     */
//    public static XmlCursor copyTable(XWPFDocument targetDocument, XmlCursor xmlCursor, XWPFTable xwpfTable) {
//
//        //目标文件 中插入一个 table
//        XWPFTable insertNewTable = targetDocument.insertNewTbl(xmlCursor);
//
//        //复制源table 样式到新的table
//        TableRowAlign tableAlignment = xwpfTable.getTableAlignment();
//        if (tableAlignment != null) {
//            insertNewTable.setTableAlignment(tableAlignment);
//        }
//
//        //获取源文件的表的行数
//        List<XWPFTableRow> rows = xwpfTable.getRows();
//        IBody body = xwpfTable.getBody();
//
//        for (int i = 0; i < rows.size(); i++) {
//
//            //源文件的 i 行
//            XWPFTableRow row_i = rows.get(i);
//
//            //第 i 行 的所有单元格
//            List<XWPFTableCell> tableCells = row_i.getTableCells();
//
//            //目标文件  table 第一行 不需要新建
//            XWPFTableRow createRow_i = null;
//            if (i == 0) {
//                createRow_i = insertNewTable.getRow(0);
//            } else {//目标文件  table 不是第一行 需要新建
//                createRow_i = insertNewTable.createRow();
//            }
//
//            //空集合
//            List<XWPFPictureData> pictures = new ArrayList<XWPFPictureData>();
//
//            //便利源文件的所有单元格
//            for (int k = 0; k < tableCells.size(); k++) {
//                //第 k 个 单元格
//                XWPFTableCell cell_k = tableCells.get(k);
//                XWPFTableCell createCell_k = null;
//                if (i == 0) {//第一行的单元格
//                    if (k == 0) {//第一行第一个单元格 不需要新建
//                        createCell_k = createRow_i.getCell(0);
//                    } else {//第一行 不是第一个单元格 需要新建
//                        createCell_k = createRow_i.createCell();
//                    }
//                } else {//不是第一行的单元格不需要新建
//                    createCell_k = createRow_i.getCell(k);
//                }
//                if (cell_k != null) {
//
//                    //移除单元格内默认的段落
//                    List<XWPFParagraph> cellParaList = createCell_k.getParagraphs();
//                    if (cellParaList != null && cellParaList.size() > 0) {
//                        createCell_k.removeParagraph(0);
//                    }
//
//                    //目标单元格 设置宽度
//                    TableWidthType widthType = cell_k.getWidthType();
//                    if (widthType != null && widthType.equals(TableWidthType.DXA)) {
//                        createCell_k.setWidth(String.valueOf(cell_k.getWidth()));
//                    }
//
//                    List<XWPFParagraph> paragraphs = cell_k.getParagraphs();
//                    for (int j = 0; j < paragraphs.size(); j++) {
//                        XWPFParagraph sourceParagraph_j = paragraphs.get(j);
//                        XWPFParagraph targetParagraph_j = createCell_k.addParagraph();
//                        copyParagraph(sourceParagraph_j, targetParagraph_j);
//                    }
//                }
//            }
//        }
//        xmlCursor = insertNewTable.getCTTbl().newCursor();
//        return xmlCursor;
//    }

//
//    /**
//     * 复制 源文件中的 table 到 目标文件
//     *
//     * @param targetDocument 目标文件 document 对象
//     * @param xwpfTable      源文件的  table
//     * @param xmlCursor      源文件的  光标
//     * @param xwpfTable      目标文件 document 中 table 的位置
//     * @return 返回光标
//     */
//    public static XmlCursor copyTableByIndex(XWPFDocument targetDocument, XWPFTable xwpfTable, XmlCursor xmlCursor, int index) {
//        targetDocument.insertNewTbl(xmlCursor);
//        targetDocument.setTable(index, xwpfTable);
//        List<XWPFTable> tables = targetDocument.getTables();
//        XWPFTable insertNewTable = tables.get(index);
//        xmlCursor = insertNewTable.getCTTbl().newCursor();
//        return xmlCursor;
//    }


    /**
     * 获取要匹配段落的位置
     *
     * @param paragraphs 所有的段落
     * @param matchKey   匹配的字符串
     * @return
     */
    public static int getPoint(List<XWPFParagraph> paragraphs, String matchKey) {
        if (matchKey.contains(" ")) {
            String[] split = matchKey.split(" ");
            matchKey = split[split.length - 1];
        }


        List<String> styleList = new ArrayList<String>(9);
        styleList.add("1");
        styleList.add("2");
        styleList.add("3");
        styleList.add("4");
        styleList.add("5");
        styleList.add("6");
        styleList.add("7");
        styleList.add("8");
        styleList.add("9");

        int startPoint = 0;
        //遍历模板中的段落对象找到标记位置

        //字符 匹配上
        for (int i = 0; i < paragraphs.size(); i++) {
            XWPFParagraph xwpfParagraph = paragraphs.get(i);

            String ptext = xwpfParagraph.getParagraphText();
            String style = xwpfParagraph.getStyle();
            if (isNullOrEmpty(ptext) || isNullOrEmpty(style)) {
                continue;
            }
            if (!styleList.contains(style)) {
                continue;
            }
            String text = xwpfParagraph.getText();
            if (text.contains(matchKey)) {
                startPoint = i;
                break;
            }
        }


        return startPoint;
    }


    /**
     * 获取要匹配段落的位置
     *
     * @param paragraphs 所有的段落
     * @param matchKey   匹配的字符串
     * @return
     */
    public static int getPoint2(List<IBodyElement> bodyElements, List<XWPFParagraph> paragraphs, String matchKey) {
        if (matchKey.contains(" ")) {
            String[] split = matchKey.split(" ");
            matchKey = split[split.length - 1];
        }

        List<String> styleList = new ArrayList<String>(9);
        styleList.add("1");
        styleList.add("2");
        styleList.add("3");
        styleList.add("4");
        styleList.add("5");
        styleList.add("6");
        styleList.add("7");
        styleList.add("8");
        styleList.add("9");

        int startPoint = 0;
        //遍历模板中的段落对象找到标记位置

        int paragraphIndex = 0;
        //int tableIndex = 0;

        for (int i = 0; i < bodyElements.size(); i++) {
            IBodyElement iBodyElement = bodyElements.get(i);

            BodyElementType elementType = iBodyElement.getElementType();
            if (elementType.equals(BodyElementType.PARAGRAPH)) {//判断 文件 body 中当前节点 是段落
                XWPFParagraph xwpfParagraph = paragraphs.get(paragraphIndex);
                paragraphIndex++;
                String ptext = xwpfParagraph.getParagraphText();
                String style = xwpfParagraph.getStyle();
                if (isNullOrEmpty(ptext) || isNullOrEmpty(style)) {
                    continue;
                }
                if (!styleList.contains(style)) {
                    continue;
                }
                String text = xwpfParagraph.getText();
                if (text.contains(matchKey)) {
                    startPoint = i;
                    break;
                }

            }
        }
        return startPoint;
    }


    /**
     * 获取要匹配段落的位置
     *
     * @param targetDocument 文档对象
     * @param matchKey       匹配的字符串
     * @return
     */
    public static int getPoint(XWPFDocument targetDocument, String matchKey) {
        //获取所有的段落
        List<XWPFParagraph> paragraphs = targetDocument.getParagraphs();
        //获取字符串位置
        return getPoint(paragraphs, matchKey);
    }


    /**
     * 获取文件中的所有段落
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    private static List<XWPFParagraph> getParagraphs(String filePath) throws IOException {
        XWPFDocument document = getDocument(filePath);
        return getParagraphs(document);
    }


    /**
     * 获取文件中的所有段落
     *
     * @param document
     * @return
     * @throws IOException
     */
    public static List<XWPFParagraph> getParagraphs(XWPFDocument document) throws IOException {
        //源文件中的段落
        List<XWPFParagraph> paraList = document.getParagraphs();
        return paraList;
    }

    /**
     * @param filePath
     * @throws IOException
     */
    public static XWPFDocument getDocument(String filePath) throws IOException {
        //源文件流
        FileInputStream fileInputStream = new FileInputStream(new File(filePath));

        //源文件的 XWPFDocument 对象
        XWPFDocument mainDocument = new XWPFDocument(fileInputStream);

        if (fileInputStream != null) {
            fileInputStream.close();
        }

        return mainDocument;

    }


    /**
     * 获取 所有的标题
     *
     * @param path
     * @return
     * @throws IOException
     */
    public static List<Map<String, String>> getWordTitles(String path) throws IOException {
        List<Map<String, String>> result = new ArrayList<Map<String, String>>();
        InputStream is = null;
        XWPFDocument doc = null;
        try {
            is = new FileInputStream(path);
            doc = new XWPFDocument(is);
            return getWordTitles(doc);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (doc != null) {
                try {
                    doc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }


    /**
     * 获取 所有的标题
     *
     * @param doc
     * @return
     * @throws IOException
     */
    public static List<Map<String, String>> getWordTitles(XWPFDocument doc) throws IOException {
        List<Map<String, String>> result = new ArrayList<Map<String, String>>();

        List<String> styleList = new ArrayList<String>(9);
        styleList.add("1");
        styleList.add("2");
        styleList.add("3");
        styleList.add("4");
        styleList.add("5");
        styleList.add("6");
        styleList.add("7");
        styleList.add("8");
        styleList.add("9");

        List<XWPFParagraph> paras = doc.getParagraphs();
        for (XWPFParagraph graph : paras) {
            String text = graph.getParagraphText();
            String style = graph.getStyle();
            if (isNullOrEmpty(text) || isNullOrEmpty(style)) {
                continue;
            }
            if (styleList.contains(style)) {
                Map map = new HashMap();
                map.put("title", text);
                map.put("level", style);
                result.add(map);
            }
        }

        return result;
    }


    /**
     * 获取 所有的标题
     *
     * @param doc
     * @return
     * @throws IOException
     */
    public static List<Map<String, String>> getWordTitles(XWPFDocument doc, List<XWPFParagraph> titleParaList) throws IOException {
        List<Map<String, String>> result = new ArrayList<Map<String, String>>();

        List<String> styleList = new ArrayList<String>(9);
        styleList.add("1");
        styleList.add("2");
        styleList.add("3");
        styleList.add("4");
        styleList.add("5");
        styleList.add("6");
        styleList.add("7");
        styleList.add("8");
        styleList.add("9");

        List<XWPFParagraph> paras = doc.getParagraphs();
        for (XWPFParagraph graph : paras) {
            String text = graph.getParagraphText();
            String style = graph.getStyle();
            if (isNullOrEmpty(text) || isNullOrEmpty(style)) {
                continue;
            }
            if (styleList.contains(style)) {
                Map map = new HashMap();
                map.put("title", text);
                map.put("level", style);
                titleParaList.add(graph);
                result.add(map);
            }
        }

        return result;
    }

    /**
     * 判空
     *
     * @param str
     * @return
     */
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.trim().length() == 0 || "null".equalsIgnoreCase(str);
    }

    /**
     * 判非空
     *
     * @param str
     * @return
     */
    public static boolean isNotNullAndNotEmpty(String str) {
        return !isNullOrEmpty(str);
    }


    /**
     * 获取同级标题的下一个标题
     *
     * @param wordTitles   所有的标题
     * @param currentTitle 当前标题
     * @return
     */
    public static Map getNextTitle(List<Map<String, String>> wordTitles, String currentTitle) {
        Map map = new HashMap();
        String nextTitle = "";
        if (currentTitle.contains(" ")) {
            String[] split = currentTitle.split(" ");
            currentTitle = split[split.length - 1];
        }
        //字符 匹配上
        int index = 0;
        for (int i = 0; i < wordTitles.size(); i++) {
            Map<String, String> map_i = wordTitles.get(i);
            String title_i = map_i.get("title");
            if (title_i.contains(currentTitle)) {
                index = i;
            }
        }
        if ((index + 1) < wordTitles.size()) {
            Map<String, String> map_i1 = wordTitles.get(index + 1);
            nextTitle = map_i1.get("title");
        }
        map.put("currentTitle", currentTitle);
        map.put("nextTitle", nextTitle);
        return map;
    }

    /**
     * 获取 两个标题在标题中的位置
     *
     * @param document
     * @param titleMap
     * @return
     */
    private static Map getTwoParagraphPoint(XWPFDocument document, Map titleMap) {
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        String currentTitle = (String) titleMap.get("currentTitle");
        String nextTitle = (String) titleMap.get("nextTitle");

        int currentPoint = getPoint(paragraphs, currentTitle);
        int nextPoint = 0;
        if (isNullOrEmpty(nextTitle)) {
            nextPoint = paragraphs.size();
        } else {
            nextPoint = getPoint(paragraphs, nextTitle);
        }
        titleMap.put("currentPoint", currentPoint);
        titleMap.put("nextPoint", nextPoint);
        return titleMap;
    }


    /**
     * 获取 两个标题在文档中的
     *
     * @param document
     * @param titleMap
     * @return
     */
    private static Map getTwoParagraphPoint2(XWPFDocument document, Map titleMap) {
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        String currentTitle = (String) titleMap.get("currentTitle");
        String nextTitle = (String) titleMap.get("nextTitle");

        List<IBodyElement> bodyElements = document.getBodyElements();

        int currentPoint = getPoint2(bodyElements, paragraphs, currentTitle);
        int nextPoint = 0;
        if (isNullOrEmpty(nextTitle)) {
            nextPoint = paragraphs.size();
        } else {
            nextPoint = getPoint2(bodyElements, paragraphs, nextTitle);
        }
        titleMap.put("currentPoint", currentPoint);
        titleMap.put("nextPoint", nextPoint);
        return titleMap;
    }


    /**
     * 复制两个点之间的内容
     *
     * @param document   源文件对象
     * @param titleMap   标题的信息
     * @param matchTitle 源文件开始标题
     * @return
     */
    private static String copyTwoPointContent(XWPFDocument document, Map titleMap, String outPath, String matchTitle) throws IOException {

        FileOutputStream fileOutputStream = null;
        XWPFDocument targetDocument = null;

        try {
            //要生成的 document
            //targetDocument = new XWPFDocument();

            //当前标题的位置
            int currentPoint = (int) titleMap.get("currentPoint");
            //下一个标题的位置
            int nextPoint = (int) titleMap.get("nextPoint");

            //获取横向设置的document
            targetDocument = getLANDSCAPEDocument();

            //源文件中的所有数据
            List<IBodyElement> bodyElements = document.getBodyElements();

            //源文件中的段落
            List<XWPFParagraph> paraList = document.getParagraphs();

            //源文件中表格
            List<XWPFTable> tables = document.getTables();

            //源文件中的图片
            List<XWPFPictureData> pictures = document.getAllPictures();

            //新建段落
            XWPFParagraph insertNewParagraph = targetDocument.createParagraph();//获取到标记位置的段落对象
            XmlCursor xmlCursor = insertNewParagraph.getCTP().newCursor();//获取到段落的光标

            List<Map> bodyEle = getBodyEle(bodyElements, paraList, tables, pictures, currentPoint, nextPoint);
            //System.out.println("bodyEle.size() : " + bodyEle.size());

            int paraIndex = 1;
            int tableIndex = 0;
            //int pictureIndex = 0;

            int beSize = bodyEle.size();
            if (beSize > 0) {
                Map map_0 = bodyEle.get(0);
                XWPFParagraph ele_0 = (XWPFParagraph) map_0.get("ele");
                //添加标题
                addTitle(targetDocument, ele_0, insertNewParagraph, matchTitle);

                for (int i = 1; i < beSize; i++) {
                    //ystem.out.println("i : " + i);

                    Map map_i = bodyEle.get(i);
                    String type_i = (String) map_i.get("type");
                    String pictureStr = (String) map_i.get("picture");
                    //Integer index = (Integer) map_i.get("index");

                    if (type_i.equals("PARAGRAPH")) {//判断 文件 body 中当前节点 是段落
                        xmlCursor.toNextSibling();//下移光标
                        XWPFParagraph paragraph_i = targetDocument.insertNewParagraph(xmlCursor);//在当前光标处插入新的段落
                        paragraph_i.setStyle("3");
                        xmlCursor = paragraph_i.getCTP().newCursor();
                        XWPFParagraph ele_i = (XWPFParagraph) map_i.get("ele");
                        if (pictureStr.equals("true")) {
                            copyParagraph(ele_i, paragraph_i);
                        } else {
                            targetDocument.setParagraph(ele_i, paraIndex);
                        }

                        xmlCursor.toNextSibling();//下移光标
                        paraIndex++;

                    } else if (type_i.equals("TABLE")) {//判断 文件 body 中当前节点 是表格
                        XWPFTable ele_i = (XWPFTable) map_i.get("ele");
                        //目标文件 中插入一个 table
                        xmlCursor.toNextSibling();
                        XWPFTable xwpfTable = targetDocument.insertNewTbl(xmlCursor);
                        xmlCursor = xwpfTable.getCTTbl().newCursor();
                        //table 添加边框
                        addTableBoder(ele_i);
                        targetDocument.setTable(tableIndex, ele_i);
                        tableIndex++;
                    }
                }
            }

            fileOutputStream = new FileOutputStream(outPath);
            targetDocument.write(fileOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (targetDocument != null) {
                try {
                    targetDocument.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        return "";

    }


    /**
     * @param oldPara
     * @param newPara
     * @param title
     */
    private static void addTitle(XWPFDocument xwpfDocument, XWPFParagraph oldPara, XWPFParagraph newPara, String title) {

        CTP ctp = newPara.getCTP();
        CTPPr ppr = ctp.isSetPPr() ? ctp.getPPr() : ctp.addNewPPr();
        CTSpacing spacing = ppr.isSetSpacing() ? ppr.getSpacing() : ppr.addNewSpacing();
        spacing.setBefore(BigInteger.valueOf(200));
        spacing.setAfter(BigInteger.valueOf(400));
        //设置行距类型为 EXACT
        spacing.setLineRule(STLineSpacingRule.EXACT);
        //1磅数是20
        //spacing.setLine(BigInteger.valueOf(5*20));

        XWPFRun titleRun = newPara.createRun();
        List<XWPFRun> runs = oldPara.getRuns();
        XWPFRun run0 = runs.get(0);
        String fontFamily = run0.getFontFamily();
        int fontSize = run0.getFontSize();


        if (isNotNullAndNotEmpty(fontFamily)) {
            titleRun.setFontFamily(fontFamily);
        } else {
            titleRun.setFontFamily("Calibri");
        }

        if (fontSize > 0) {
            titleRun.setFontSize(fontSize);
            titleRun.setBold(true);
        } else {
            titleRun.setFontSize(16);
            titleRun.setBold(true);
        }

        titleRun.setText(title);
        //添加标题
        ParagraphAlignment alignment_0 = oldPara.getAlignment();
        if (alignment_0 != null) {
            newPara.setAlignment(alignment_0);
        }

    }


    /**
     * 输出图片到本地
     *
     * @param pictures
     * @param dir
     * @throws IOException
     */
    private void outPictureToLocal(List<XWPFPictureData> pictures, String dir) throws IOException {
        for (int i = 0; i < pictures.size(); i++) {
            if (i >= pictures.size()) {
                return;
            }
            XWPFPictureData xwpfPictureData_i = pictures.get(i);
            byte[] data_i = xwpfPictureData_i.getData();
            String picName = "drw-" + i + ".png";
            FileOutputStream out = new FileOutputStream(dir + File.separator + picName);
            out.write(data_i);
            out.flush();
        }
    }


    /**
     * 获取横向设置的document
     *
     * @return
     */
    private static XWPFDocument getLANDSCAPEDocument() throws XmlException, IOException {
        //要生成的 document
        XWPFDocument docx = new XWPFDocument();
        //CTStyles styles = docx.getStyle();
        //XWPFStyles docStyle  = docx.createStyles();

        CTDocument1 ctd = docx.getDocument();
        CTBody body = ctd.getBody();
        if (!body.isSetSectPr()) {
            body.addNewSectPr();
        }
        CTSectPr section = body.getSectPr();
        if (!section.isSetPgSz()) {
            section.addNewPgSz();
        }
        CTPageSz pageSize = section.getPgSz();
        CTPageMar pgMar = section.getPgMar();
        if (pgMar == null) {
            section.addNewPgMar();
            pgMar = section.getPgMar();
        }
        //设置边距
        pgMar.setLeft(BigInteger.valueOf(720L));
        pgMar.setTop(BigInteger.valueOf(1440L));
        pgMar.setRight(BigInteger.valueOf(720L));
        pgMar.setBottom(BigInteger.valueOf(1440L));

        // 设置页面大小  当前A4大小
        pageSize.setW(BigInteger.valueOf(16840));
        pageSize.setH(BigInteger.valueOf(11907));

        //设置布局为横向
        pageSize.setOrient(STPageOrientation.LANDSCAPE);

        return docx;
    }


    /**
     * 获取两个标题间所有的元素
     *
     * @param bodyElements word 所有的页面元素
     * @param paraList     段落集合
     * @param tables       表格集合
     * @param pictures     图片集合
     * @param ipstart      段落的开始位置
     * @param ipend        段落的结束位置
     * @return
     */
    private static List<Map> getBodyEle(List<IBodyElement> bodyElements, List<XWPFParagraph> paraList, List<XWPFTable> tables, List<XWPFPictureData> pictures, int ipstart, int ipend) {
        List<Map> result = new ArrayList<Map>();

        int paraIndex = 0;
        int tableIndex = 0;
        int pictureIndex = 0;

        for (int i = 0; i < bodyElements.size(); i++) {
            IBodyElement iBodyElement = bodyElements.get(i);//获得传过来的段落对象
            BodyElementType elementType = iBodyElement.getElementType();

            if (elementType.equals(BodyElementType.PARAGRAPH)) {//判断 文件 body 中当前节点 是段落
                XWPFParagraph xwpfParagraph = paraList.get(paraIndex);
                List<XWPFRun> runs = xwpfParagraph.getRuns();//获取run对象

                boolean flag = true;
                for (int k = 0; k < runs.size(); k++) {
                    XWPFRun oldRun = runs.get(k);
                    CTR oldCtr = oldRun.getCTR();
                    List<CTDrawing> drawingList = oldCtr.getDrawingList();
                    if (drawingList.size() > 0) {
                        //判断是图片  图片计数器++
                        flag = false;
                        break;
                    }
                }

                if (paraIndex >= ipstart && paraIndex < ipend) {
                    Map map = new HashMap();
                    map.put("ele", xwpfParagraph);
                    map.put("type", "PARAGRAPH");
                    if (flag) {
                        map.put("picture", "false");
                        map.put("index", paraIndex);
                    } else {
                        map.put("picture", "true");
                        map.put("index", pictureIndex);
                    }
                    result.add(map);
                }


                paraIndex++;
                if (!flag) {
                    pictureIndex++;
                }

            } else if (elementType.equals(BodyElementType.TABLE)) {//判断 文件 body 中当前节点 是表格

                XWPFTable xwpfTable = tables.get(tableIndex);
                if (paraIndex >= ipstart && paraIndex < ipend) {
                    Map map = new HashMap();
                    map.put("ele", xwpfTable);
                    map.put("type", "TABLE");
                    map.put("picture", "false");
                    map.put("index", tableIndex);
                    result.add(map);
                }
                tableIndex++;
            }

        }
        return result;
    }

//    /**
//     * @param paragraphList
//     */
//    private static void getTitleLevel(List<XWPFParagraph> paragraphList) {
//        int[] levelCurrentValues = new int[]{0, 0, 0};
//
//        for (XWPFParagraph paragraph : paragraphList) {
//
//            String levelText = paragraph.getNumLevelText();
//
//            BigInteger levelDepth = paragraph.getNumIlvl();
//
//            String levelFormat = paragraph.getNumFmt();
//
//            System.out.println("text: " + levelText);
//
//            System.out.println("depth: " + levelDepth);
//
//            System.out.println("format: " + levelFormat);
//
//            if (levelText != null) {
//
//                levelCurrentValues[levelDepth.intValue()] += 1;
//
//                levelText = levelText.replace("%1", "" + levelCurrentValues[0]);
//
//                levelText = levelText.replace("%2", "" + levelCurrentValues[1]);
//
//                levelText = levelText.replace("%3", "" + levelCurrentValues[2]);
//
//
//                System.out.println(levelText);
//
//                System.out.println("");
//
//            }
//
//        }
//    }


    /**
     * 生成文件的章节
     *
     * @param sourcePath
     * @param targetPath
     * @param matchTitle
     */
    public static void createNodeFile(String sourcePath, String targetPath, String matchTitle) throws IOException {
        //拆分出来一部分文件
        InputStream is = null;
        XWPFDocument doc = null;
        try {
            is = new FileInputStream(sourcePath);
            doc = new XWPFDocument(is);

            //标题的段落集合
            List<XWPFParagraph> titleParaList = new ArrayList<XWPFParagraph>();

            //获取标题集合
            List<Map<String, String>> wordTitles = getWordTitles(doc, titleParaList);
            //System.out.println("wordTitles : " + wordTitles);

            //获取到当前标题和下一个标题
            Map titleMap = getNextTitle(wordTitles, matchTitle);
            //System.out.println("titleMap : " + titleMap);

            //获取标题的位置
            titleMap = getTwoParagraphPoint(doc, titleMap);
            //System.out.println("titleMap : " + titleMap);

            //复制两个标题中间的内容 到指定的文件
            copyTwoPointContent(doc, titleMap, targetPath, matchTitle);

        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (doc != null) {
                try {
                    doc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 清除文件中的内容
     *
     * @param doc        document
     * @param startPoint 开始位置
     * @param endPoint   结束位置
     */
    public static void clearBodyContent(XWPFDocument doc, Integer startPoint, Integer endPoint) {

        List<IBodyElement> bodyElements = doc.getBodyElements();

        //List<IBodyElement> removeEles = new ArrayList<IBodyElement>();
        for (int i = bodyElements.size() - 1; i > -1; i--) {
            //bodyElements
            if (i > startPoint && i < endPoint) {
                //removeEles.add(bodyElements.get(i));
                doc.removeBodyElement(i);
            }
        }
    }

    /**
     * 清空章节下的内容
     *
     * @param sourcePath
     * @param title
     */
    public static void removeTitleContent(String sourcePath, String title) throws Exception {
        //拆分出来一部分文件
        InputStream is = null;
        XWPFDocument doc = null;
        FileOutputStream out = null;
        try {
            is = new FileInputStream(sourcePath);
            doc = new XWPFDocument(is);

            //移除标题内容
            removeTitleContent(doc, title);

            //更新文件
            out = new FileOutputStream(sourcePath);
            doc.write(out);

        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (doc != null) {
                try {
                    doc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 清空章节下的内容
     *
     * @param doc
     * @param title
     */
    public static void removeTitleContent(XWPFDocument doc, String title) throws Exception {

        //标题的段落集合
        //List<XWPFParagraph> titleParaList = new ArrayList<XWPFParagraph>();

        //获取标题集合
        List<Map<String, String>> wordTitles = getWordTitles(doc);
        //System.out.println("wordTitles : " + wordTitles);

        //获取到当前标题和下一个标题
        Map titleMap = getNextTitle(wordTitles, title);
        //System.out.println("titleMap : " + titleMap);

        //获取标题的位置
        titleMap = getTwoParagraphPoint2(doc, titleMap);
        //System.out.println("titleMap : " + titleMap);

        int startPoint = (int) titleMap.get("currentPoint");
        int endPoint = (int) titleMap.get("nextPoint");

        clearBodyContent(doc, startPoint, endPoint);
    }


    /**
     * 替换章节下的内容
     *
     * @param wholeFilePath 整体文件路径
     * @param nodeFilePath  章节文件路径
     * @param title         标题
     */
    public static void replaceTitleContent(String wholeFilePath, String nodeFilePath, String title) throws Exception {
        //拆分出来一部分文件
        InputStream is = null;
        XWPFDocument doc = null;
        FileOutputStream out = null;
        try {
            is = new FileInputStream(wholeFilePath);
            doc = new XWPFDocument(is);

            //移除标题下的内容
            removeTitleContent(doc, title);

            XWPFDocument nodeDocument = getDocument(nodeFilePath);

            //标题下添加内容
            convert(nodeDocument, doc, wholeFilePath, title);

            out = new FileOutputStream(wholeFilePath);
            doc.write(out);


        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (doc != null) {
                try {
                    doc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 获取 指定标题下 一个个表格的序号
     *
     * @param doc
     * @param title
     * @return
     */
    public static int getTitleTableIndex(XWPFDocument doc, String title) {
        List<IBodyElement> bodyElements = doc.getBodyElements();
        List<XWPFParagraph> paragraphs = doc.getParagraphs();
        return getTitleTableIndex(bodyElements, paragraphs, title);
    }

    /**
     * 获取 指定标题下 一个个表格的序号
     *
     * @param bodyElements
     * @param paragraphs
     * @param title
     * @return
     */
    public static int getTitleTableIndex(List<IBodyElement> bodyElements, List<XWPFParagraph> paragraphs, String title) {
        Integer result = 0;
        if (title.contains(" ")) {
            String[] split = title.split(" ");
            title = split[split.length - 1];
        }
        List<String> styleList = new ArrayList<String>(9);
        styleList.add("1");
        styleList.add("2");
        styleList.add("3");
        styleList.add("4");
        styleList.add("5");
        styleList.add("6");
        styleList.add("7");
        styleList.add("8");
        styleList.add("9");
        int paragraphIndex = 0;
        //int tableIndex = 0;
        for (int i = 0; i < bodyElements.size(); i++) {
            IBodyElement iBodyElement = bodyElements.get(i);
            BodyElementType elementType = iBodyElement.getElementType();
            if (elementType.equals(BodyElementType.PARAGRAPH)) {//判断 文件 body 中当前节点 是段落
                XWPFParagraph xwpfParagraph = paragraphs.get(paragraphIndex);
                paragraphIndex++;
                String ptext = xwpfParagraph.getParagraphText();
                String style = xwpfParagraph.getStyle();
                if (isNullOrEmpty(ptext) || isNullOrEmpty(style)) {
                    continue;
                }
                if (!styleList.contains(style)) {
                    continue;
                }
                String text = xwpfParagraph.getText();
                if (text.contains(title)) {
                    break;
                }
            } else if (elementType.equals(BodyElementType.TABLE)) {
                result++;
            }
        }
        return result;

    }


    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {
//        String sourcePath = "D:\\svncode\\GW_2021x\\新建文件夹\\测试示例数据\\word\\wordceshi.docx";
//        String targetPath = "D:\\svncode\\GW_2021x\\新建文件夹\\测试示例数据\\word\\wordceshi-copy.docx";
//        String matchTitle = "4.1.3 BM3-X1";

//        String sourcePath = "C:\\temp\\1649416457505-0740\\XAST-T0005健康评估.docx";
//        String targetPath = "C:\\temp\\1649416457505-0740\\4.6 测控分系统健康评估.docx";
//        String matchTitle = "4.6 测控分系统健康评估";


        String sourcePath = "C:\\temp\\1649642380481-2223\\XAST-T0006健康评估.docx";
        String targetPath = "C:\\temp\\1649642380481-2223\\4.5 热控分系统健康评估.docx";
        String matchTitle = "4.5 热控分系统健康评估";
        try {
            //复制标题的内容到新的文件
            //createNodeFile(sourcePath, targetPath, matchTitle);

            //清除指定标题的内容
            //removeTitleContent(sourcePath, matchTitle);

            //替换标题的内容
            //replaceTitleContent(sourcePath, targetPath, matchTitle);

            convert(targetPath, sourcePath, matchTitle);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}


